Parte 2: Intro al Aprendizaje Federado

En la sección previa, aprendimos sobre punteros de tensores (PointerTensors), que crean la infraestructura subyacente que necesitamos para preservar la privacidad con aprendizaje profundo. En esta sección, veremos cómo utilizar estas herramientas básicas para implementar nuestro primer algoritmo de aprendizaje profundo con preservación de privacidad, el aprendizaje federado.

Autores:

Traductores:

¿Qué es el aprendizaje federado?

Es una manera simple y poderosa para entrenar modelos de aprendizaje profundo. Si piensas sobre datos de entrenamiento, siempre son el resultado de algún tipo de proceso de recolección. La gente (por medio de dispositivos) generan datos al registrar eventos del mundo real. Normalmente, estos datos son agregados a una ubicación central y única de tal manera que uno pueda entrenar un modelo de aprendizaje de máquina. El aprendizaje federado le da la vuelta a esto.

En lugar de llevar los datos de entrenamiento al modelo (o servidor central), uno lleva el modelo a los datos de entraniento (donde sea que que esté).

La idea es que esto la única copia permanente de los datos pertenece a quien los está creando, y así mantiene el control de su acceso. Cool, no?

2.1 Un Ejemplo de Aprendizaje Federado de Juguete

Comencemos entrenando un modelo de juguete con el método centralizado. Este modelo es de lo más simple. Primero necesitamos:

  • Un conjunto de datos de juguete
  • Un modelo
  • Una lógica de entrenamiento básica para que el modelo se ajuste a los datos.

Nota: Si esta API no te es familiar visita fast.ai y toma el curso antes de continuar con este tutorial.


In [ ]:
import torch
from torch import nn
from torch import optim

In [ ]:
# Un conjunto de datos de juguete
data = torch.tensor([[0,0],[0,1],[1,0],[1,1.]], requires_grad=True)
target = torch.tensor([[0],[0],[1],[1.]], requires_grad=True)

# Un modelo de juguete.
model = nn.Linear(2,1)

def train():
    # Lógica de entrenamiento
    opt = optim.SGD(params=model.parameters(),lr=0.1)
    for iter in range(20):

        # 1) borra los gradientes previos (si existen)
        opt.zero_grad()

        # 2) haz una predicción
        pred = model(data)

        # 3) calcula cuál fue la pérdida
        loss = ((pred - target)**2).sum()

        # 4) encuentra los pesos que causaron la pérdida
        loss.backward()

        # 5) cambia esos pesos
        opt.step()

        # 6) imprime nuesto progreso
        print(loss.data)

In [ ]:
train()

¡Y ahí lo tienes! Hemos entrenado un modelo básico con un método convencional. Todos nuestros datos están agregados en nuestra máquina local y podemos usarlos para hacerle actualizaciones al modelo. El aprendizaje federado, sin embargo, no funciona así. Así que modifiquemos este ejemplo para hacerlo con aprendizaje federado.

Lo que necesitamos:

  • Crear un par de trabajadores
  • Hacer que los punteros entrenen los datos en cada trabajador.
  • Actualizar la lógica de entrenamiento para que haga aprendizaje federado.

    Nuevos Pasos de Entrenamiento:

    • Mandar el modelo al trabajador correcto.
    • Entrenarlo con los datos que se encuentran ahí.
    • Recuperar el modelo y repetir con el próximo trabajador.

In [ ]:
import syft as sy
hook = sy.TorchHook(torch)

In [ ]:
# Crear un par de trabajadores

bob = sy.VirtualWorker(hook, id="bob")
alice = sy.VirtualWorker(hook, id="alice")

In [ ]:
# Un conjunto de datos de juguete
data = torch.tensor([[0,0],[0,1],[1,0],[1,1.]], requires_grad=True)
target = torch.tensor([[0],[0],[1],[1.]], requires_grad=True)

# Hacer que los punteros entrenen los datos en 
# cada trabajador mandando datos a bob y alice
data_bob = data[0:2]
target_bob = target[0:2]

data_alice = data[2:]
target_alice = target[2:]

# Inicializar un modelo de juguete
model = nn.Linear(2,1)

data_bob = data_bob.send(bob)
data_alice = data_alice.send(alice)
target_bob = target_bob.send(bob)
target_alice = target_alice.send(alice)

# Organizar los punteros en una lista
datasets = [(data_bob,target_bob),(data_alice,target_alice)]

opt = optim.SGD(params=model.parameters(),lr=0.1)

In [ ]:
def train():
    # Lógica de entrenamiento
    opt = optim.SGD(params=model.parameters(),lr=0.1)
    for iter in range(10):
        
        # NUEVO) Itera sobre el conjunto de datos de cada trabajador
        for data,target in datasets:
            
            # NUEVO) Manda el modelo a el trabajador correcto
            model.send(data.location)

            # 1) borra los gradientes previos (si existen)
            opt.zero_grad()

            # 2) haz una predicción
            pred = model(data)

            # 3) calcula cuál fue la pérdida
            loss = ((pred - target)**2).sum()

            # 4) encuentra los pesos que causaron la pérdida
            loss.backward()

            # 5) cambia esos pesos
            opt.step()
            
            # NUEVO recupera el modelo (con gradientes)
            model.get()

            # 6) imprime nuestro progreso
            print(loss.get()) # NUEVO) Necesitamos llamar a .get()
    
# federated averaging

In [ ]:
train()

¡Muy bien!

¡Y voilà! Ahora estamos entrenando un modelo de aprendizaje profundo muy simple utilizando aprendizaje federado. Mandamos el modelo a cada trabajador, generamos un nuevo gradiente, y luego recuperamos el gradiente en nuestro servidor local donde actualizamos nuestro modelo global. En ningún punto de este proceso vemos o requerimos acceso al conjunto de datos de entrenamiento subyacente. ¡Preservamos la privacidad de Bob y Alice!

Algunos defectos de este ejemplo

Aunque este ejemplo es una buena introducción al aprendizaje federado, aún tiene algunos defectos importantes. Notablemente, cuando llamamos model.get() y recibimos el modelo actualizado de Bob o Alice de hecho podemos aprender mucho sobre el conjunto de entrenamiento de Bob/Alice sólo con la información de sus gradientes. ¡En algunos casos, podemos restaurar el conjunto de entrenamiento a la perfección!

Así que, ¿qué podemos hacer? Bueno, la primera estrategia que utiliza la gente es promediar el gradiente sobre múltiples individuos antes de actulizarlo en el servidor central. Esta estrategia, sin embargo, requiere el uso de objetos PointerTensor más sofisticados. Entonces, en la siguiente sección nos tomaremos un tiempo para aprender un poco de la funcionalidad avanzada de los punteros y actualizaremos este ejemplo de aprendizaje federado.

!Felicitaciones! - !Es hora de unirte a la comunidad!

¡Felicitaciones por completar esta parte del tutorial! Si te gustó y quieres unirte al movimiento para preservar la privacidad, propiedad descentralizada de IA y la cadena de suministro de IA (datos), puedes hacerlo de las ¡siguientes formas!

Dale una estrella a PySyft en GitHub

La forma más fácil de ayudar a nuestra comunidad es por darle estrellas a ¡los repositorios de Github! Esto ayuda a crear consciencia de las interesantes herramientas que estamos construyendo.

¡Únete a nuestro Slack!

La mejor manera de mantenerte actualizado con los últimos avances es ¡unirte a la comunidad! Tú lo puedes hacer llenando el formulario en http://slack.openmined.org

¡Únete a un proyecto de código!

La mejor manera de contribuir a nuestra comunidad es convertirte en un ¡contribuidor de código! En cualquier momento puedes ir al Github Issues de PySyft y filtrar por "Proyectos". Esto mostrará todos los tiquetes de nivel superior dando un resumen de los proyectos a los que ¡te puedes unir! Si no te quieres unir a un proyecto, pero quieres hacer un poco de código, también puedes mirar más mini-proyectos "de una persona" buscando por Github Issues con la etiqueta "good first issue".

Donar

Si no tienes tiempo para contribuir a nuestra base de código, pero quieres ofrecer tu ayuda, también puedes aportar a nuestro Open Collective". Todas las donaciones van a nuestro web hosting y otros gastos de nuestra comunidad como ¡hackathons y meetups!

OpenMined's Open Collective Page


In [ ]:


In [ ]: